package cn.wch.meshlib.frame;

import androidx.annotation.NonNull;

import java.nio.ByteBuffer;

import cn.wch.meshlib.constant.Command;

/**
 * 数据包生成实用程序（需要传输的控制命令数据包）
 */
public class CommandGenerateUtil {
    /**外围命令长度*/
    private static final int PERIPHERAL_CMD_LEN=1;
    /**服务密钥长度*/
    private static final int PROVISION_NET_KEY_LEN=16;
    /**地址长度*/
    private static final int ADDRESS_LEN=2;
    /**OTA升级地址长度*/
    private static final int UPDATE_ADDRESS_LEN=2;
    /**状态码长度*/
    private static final int STATUS_CODE_LEN=1;
    private static final int IV_INDEX_LEN=4;
    /**标志位长度*/
    private static final int FLAG_LEN=1;
    /**控制码长度*/
    private static final int CONTROL_CODE_LEN=1;

    /**
     * 获取供应信息命令
     * @param control_code 控制代码
     * @param iv_index
     * @param flag
     * @return
     */
    public static byte[] getProvisionInfoCommand(byte control_code,byte[] iv_index,byte flag){
        ByteBuffer byteBuffer=ByteBuffer.allocate(PERIPHERAL_CMD_LEN+CONTROL_CODE_LEN+IV_INDEX_LEN+FLAG_LEN);
        byteBuffer.put(Command.CMD_PROVISION_INFO);
        byteBuffer.put(control_code);
        byteBuffer.put(trimByteArray(iv_index,IV_INDEX_LEN));
        byteBuffer.put(flag);
        return byteBuffer.array();
    }

    /**
     * 获取配置命令
     * @param key
     * @param address
     * @return
     */
    public static byte[] getProvisionCommand(byte[] key,byte[] address){
        ByteBuffer byteBuffer=ByteBuffer.allocate(PERIPHERAL_CMD_LEN+PROVISION_NET_KEY_LEN+ADDRESS_LEN);
        byteBuffer.put(Command.CMD_PROVISION);
        byteBuffer.put(trimByteArray(key,PROVISION_NET_KEY_LEN));
        byteBuffer.put(trimByteArray(flipByteArray(address),ADDRESS_LEN));
        return byteBuffer.array();
    }

    /**
     * 获取删除节点命令
     * @param address
     * @return
     */
    public static byte[] getDeleteNodeCommand(byte[] address){
        ByteBuffer byteBuffer=ByteBuffer.allocate(PERIPHERAL_CMD_LEN+ADDRESS_LEN);
        byteBuffer.put(Command.CMD_DELETE_NODE);
        byteBuffer.put(trimByteArray(flipByteArray(address),ADDRESS_LEN));
        return byteBuffer.array();
    }

//    public static byte[] getDeleteNodeStorageCommand(){
//        ByteBuffer byteBuffer=ByteBuffer.allocate(PERIPHERAL_CMD_LEN);
//        byteBuffer.put(Command.CMD_DELETE_NODE_INFO);
//        return byteBuffer.array();
//    }

    /**
     * 获取查询节点状态命令
     * @param address
     * @return
     */
    public static byte[] getQueryNodeStateCommand(byte[] address){
        ByteBuffer byteBuffer=ByteBuffer.allocate(PERIPHERAL_CMD_LEN+ADDRESS_LEN);
        byteBuffer.put(Command.CMD_ASK_STATUS);
        byteBuffer.put(trimByteArray(flipByteArray(address),ADDRESS_LEN));
        return byteBuffer.array();
    }

    /**
     * 获取数据传输命令
     * @param address
     * @param data
     * @return
     */
    public static byte[] getTransferDataCommand(byte[] address,byte[] data){
        ByteBuffer byteBuffer=ByteBuffer.allocate(PERIPHERAL_CMD_LEN+ADDRESS_LEN+data.length);
        byteBuffer.put(Command.CMD_TRANSFER);
        byteBuffer.put(trimByteArray(flipByteArray(address),ADDRESS_LEN));
        byteBuffer.put(data);
        return byteBuffer.array();
    }

    /**
     * 获取OTA查询节点图像命令
     * @param address
     * @return
     */
    public static byte[] getOTAQueryNodeImageCommand(byte[] address){
        ByteBuffer byteBuffer=ByteBuffer.allocate(PERIPHERAL_CMD_LEN+ADDRESS_LEN);
        byteBuffer.put(Command.CMD_IMAGE_INFO);
        byteBuffer.put(trimByteArray(flipByteArray(address),ADDRESS_LEN));
        return byteBuffer.array();
    }

    /**
     * 获取OTA更新命令
     * @param address
     * @param flashAddress
     * @param data
     * @param offset
     * @param length
     * @return
     */
    public static byte[] getOTAUpdateCommand(byte[] address,int flashAddress,byte[] data,int offset,int length){
        ByteBuffer byteBuffer=ByteBuffer.allocate(PERIPHERAL_CMD_LEN+ADDRESS_LEN+UPDATE_ADDRESS_LEN+length);
        byteBuffer.put(Command.CMD_UPDATE);
        byteBuffer.put(trimByteArray(flipByteArray(address),ADDRESS_LEN));
        byteBuffer.put((byte) (flashAddress & 0x000000ff));
        byteBuffer.put((byte) ((flashAddress & 0x0000ff00) >>8));
        byteBuffer.put(data,offset,length);
        return byteBuffer.array();
    }

    /**
     * 获取OTA验证命令
     * @param address
     * @param flashAddress
     * @param data
     * @param offset
     * @param length
     * @return
     */
    public static byte[] getOTAVerifyCommand(byte[] address,int flashAddress,byte[] data,int offset,int length){
        ByteBuffer byteBuffer=ByteBuffer.allocate(PERIPHERAL_CMD_LEN+ADDRESS_LEN+UPDATE_ADDRESS_LEN+length);
        byteBuffer.put(Command.CMD_VERIFY);
        byteBuffer.put(trimByteArray(flipByteArray(address),ADDRESS_LEN));
        byteBuffer.put((byte) (flashAddress & 0x000000ff));
        byteBuffer.put((byte) ((flashAddress & 0x0000ff00) >>8));
        byteBuffer.put(data,offset,length);
        return byteBuffer.array();
    }

    /**
     * 获取OTA结束命令
     * @param address
     * @return
     */
    public static byte[] getOTAEndCommand(byte[] address){
        ByteBuffer byteBuffer=ByteBuffer.allocate(PERIPHERAL_CMD_LEN+ADDRESS_LEN);
        byteBuffer.put(Command.CMD_END_INFO);
        byteBuffer.put(trimByteArray(flipByteArray(address),ADDRESS_LEN));
        return byteBuffer.array();
    }

    /**
     * 获取订阅命令
     * @param nodeAddress 订阅的目标节点地址
     * @param controlCode 控制码
     * @param groupAddress 订阅的目标组地址
     * @return
     */
    public static byte[] getSubscribeNodeCommand(byte[] nodeAddress,byte controlCode,byte[] groupAddress){
        ByteBuffer byteBuffer=ByteBuffer.allocate(PERIPHERAL_CMD_LEN+ADDRESS_LEN+CONTROL_CODE_LEN+ADDRESS_LEN);
        byteBuffer.put(Command.CMD_SET_SUB);
        byteBuffer.put(trimByteArray(flipByteArray(nodeAddress),ADDRESS_LEN));
        byteBuffer.put(controlCode);
        byteBuffer.put(trimByteArray(flipByteArray(groupAddress),ADDRESS_LEN));
        return byteBuffer.array();
    }

    /**
     * 获取复位命令
     * @return
     */
    public static byte[] getResetCommand(){
        ByteBuffer byteBuffer=ByteBuffer.allocate(PERIPHERAL_CMD_LEN);
        byteBuffer.put(Command.CMD_LOCAL_RESET);
        return byteBuffer.array();
    }

    /**
     * 裁剪字节数组
     * @param data 需要裁剪的字节数组
     * @param except 裁剪位置
     * @return
     */
    private static byte[] trimByteArray(byte[] data, int except){
        if(data==null){
            return new byte[except];
        }
        if(except==data.length){
            return data;
        }
        byte[] temp=new byte[except];
        System.arraycopy(data,0,temp,0,Math.min(data.length,except));
        return temp;
    }

    /**
     * 翻转字节数组（按首位向尾调换方式翻转）
     * @param data 需要翻转的源数据
     * @return 返回翻转后的新数据
     */
    public static byte[] flipByteArray(@NonNull byte[] data){
        byte[] target=new byte[data.length];

        for(int i=0;i<data.length;i++){
            target[i]=data[data.length-1-i];
        }
        return target;
    }
}
